package site.ruyi.devclient.client.ftp.impl;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;

import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javafx.scene.control.PasswordField;
import javafx.scene.control.TextField;
import site.ruyi.devclient.client.ftp.IFtpClient;
import site.ruyi.devclient.client.ftp.RemoteFileAttr;
import site.ruyi.devclient.core.FormDialog;
import site.ruyi.devclient.core.UserData;
import site.ruyi.devclient.util.FTPUtil;
import site.ruyi.devclient.util.FormatUtil;

public class FtpClientImpl implements IFtpClient {

	private static final Logger log=LoggerFactory.getLogger(FtpClientImpl.class);

	private static final String CLIENT_NAME="FTP";

	private static final String FILE_DATE_FORMAT_STR = "yyyy-MM-dd HH:mm:ss";

	private FTPUtil ftpUtil;

	private RemoteShellOutputListener remoteShellOutputListener;

	public FtpClientImpl(){
		UserData.getDB().exec("CREATE TABLE IF NOT EXISTS ftp_client(id TEXT NOT NULL ON CONFLICT FAIL UNIQUE ON CONFLICT REPLACE,host TEXT,port TEXT,username TEXT,password TEXT,create_time TIMESTAMP default (datetime('now', 'localtime')))");
	}

	@Override
	public void close() throws IOException {
		if(ftpUtil!=null){
			ftpUtil.close();
		}
	}

	@Override
	public String getName() {
		return CLIENT_NAME;
	}

	@Override
	public boolean init(RemoteShellOutputListener remoteShellOutputListener) {
		log.info("初始化客户端组件！");
		this.remoteShellOutputListener=remoteShellOutputListener;
		if(createConnection()){
			remoteShellOutputListener.handle("已连接！\n");
			return true;
		}
		return false;
	}

	private boolean createConnection() {
		log.info("创建连接！");
		TextField hostTextField = new TextField("127.0.0.1");
		TextField portTextField = new TextField("21");
		TextField userTextField = new TextField();
		PasswordField pwdTextField = new PasswordField();

		Map<String,Object> lastConnInfo=UserData.getDB().find("select host,port,username,password from ftp_client order by create_time desc limit 1");
		if(lastConnInfo!=null&&!lastConnInfo.isEmpty()){
			hostTextField.setText(String.valueOf(lastConnInfo.get("host")));
			portTextField.setText(String.valueOf(lastConnInfo.get("port")));
			userTextField.setText(String.valueOf(lastConnInfo.get("username")));
			pwdTextField.setText(String.valueOf(lastConnInfo.get("password")));
		}

		FormDialog newConnForm = new FormDialog("新建链接"
				,new FormDialog.Item("主机：", hostTextField)
				,new FormDialog.Item("端口：", portTextField)
				,new FormDialog.Item("用户名：", userTextField)
				,new FormDialog.Item("密码：", pwdTextField));
		Optional<Boolean> result = newConnForm.showAndWait();
		if(result.isPresent()) {
			String host = hostTextField.getText();
			int port = Integer.valueOf(portTextField.getText());
			String username = userTextField.getText();
			String password = pwdTextField.getText();
			log.info("连接参数 -> host:"+host+",port:"+port);
			ftpUtil=FTPUtil.getFTPClient(host, port, username, password);

			String connId=DigestUtils.md5Hex(host+"_"+port+"_"+username+"_"+password);
			UserData.getDB().save("insert into ftp_client(id,host,port,username,password) values(?,?,?,?,?)", connId,host,port,username,password);

			return true;
		}
		return false;
	}

	@Override
	public void exeCmd(String cmd) {
		ftpUtil.run((FTPClient ftpClient)->{
			ftpClient.sendCommand(utf2iso(cmd));
			String[] resultStrs=ftpClient.getReplyStrings();
			for(int i=0;i<resultStrs.length;i++){
				remoteShellOutputListener.handle(resultStrs[i]);
			}
		});
	}

	@Override
	public String pwd() {
		StringBuilder strBuilder=new StringBuilder();
		ftpUtil.run((FTPClient ftpClient)->{
			String currDir=ftpClient.printWorkingDirectory();
			strBuilder.append(currDir);
		});
		return strBuilder.toString();
	}

	@Override
	public List<RemoteFileAttr> listFile(String remotePath) {
		List<RemoteFileAttr> fileList=new ArrayList<>();
		ftpUtil.run((FTPClient ftpClient)->{
			FTPFile[] files = ftpClient.listFiles(remotePath);
			for(FTPFile file:files){
				String fileName = iso2utf(file.getName());
				String fileSize = FormatUtil.formatFileSize(file.getSize());
				String lastUpdateTime = FormatUtil.formatDate(file.getTimestamp().getTimeInMillis(),FILE_DATE_FORMAT_STR);
				String permissionsStr = file.getGroup()+"/"+file.getUser();
				boolean isDir = file.isDirectory();
				fileList.add(new RemoteFileAttr(fileName, fileSize, lastUpdateTime, permissionsStr, isDir));
			}
		});
		return fileList;
	}

	@Override
	public void delFile(String remoteFilePath,boolean isDir) {
		ftpUtil.run((FTPClient ftpClient)->{
			if(isDir){
				ftpClient.rmd(utf2iso(remoteFilePath));
			}else{
				ftpClient.deleteFile(utf2iso(remoteFilePath));
			}
		});
	}

	@Override
	public void upload(String localFilePath, String remoteFilePath) {
		ftpUtil.run((FTPClient ftpClient)->{
			File remoteFile=new File(remoteFilePath);
			ftpClient.changeWorkingDirectory(utf2iso(remoteFile.getParent()));
			ftpClient.storeFile(utf2iso(remoteFile.getName()), new FileInputStream(localFilePath));
		});
	}

	@Override
	public void download(String remoteFilePath, String localFilePath) {
		ftpUtil.run((FTPClient ftpClient)->{
			File remoteFile=new File(remoteFilePath);
			ftpClient.changeWorkingDirectory(utf2iso(remoteFile.getParent()));
			ftpClient.retrieveFile(utf2iso(remoteFile.getName()), new FileOutputStream(localFilePath));
		});
	}

	@Override
	public void sendHotKey(HotKey hotKey) {
		throw new UnsupportedOperationException("未支持的操作！");
	}

	private static String iso2utf(String str){
		if(StringUtils.isBlank(str)) return "";
		return new String(str.getBytes(StandardCharsets.ISO_8859_1),StandardCharsets.UTF_8);
	}

	private static String utf2iso(String str){
		if(StringUtils.isBlank(str)) return "";
		return new String(str.getBytes(StandardCharsets.UTF_8),StandardCharsets.ISO_8859_1);
	}
}
